<?php

namespace app\common\model\banxi\trainer;

use app\common\enums\SexEnum;
use app\common\enums\TrainerCheckEnum;
use app\common\enums\TrainerLevelEnum;
use app\common\enums\TrainerPracticeEnum;
use app\common\enums\TrainerStatusEnum;
use app\common\model\banxi\core\CoreTrainerTime;
use app\common\model\banxi\learn\LearnSkRecord;
use app\common\model\banxi\organization\Organization;
use app\common\model\banxi\organization\Organization as OrganizationModel;
use app\common\model\common\BaseModel;
use ba\Exception;
use think\db\exception\PDOException;
use think\exception\ValidateException;
use think\Model;
use think\model\concern\SoftDelete;

/**
 * 教练
 */
class Trainer extends BaseModel
{

    use SoftDelete;

    protected $name = 'banxi_trainer';

    protected $autoWriteTimestamp = true;

    protected $deleteTime = 'del';

    protected $defaultSoftDelete = 0;

    protected $append = [
        'checkCn',
        'levelCn',
        'practiceCn',
        'sexCn',
        'statusCn'
    ];
    protected $type = [
        'id' => 'string',
        'del' => 'string',
        'title' => 'string',
        'isPublic' => 'boolean',
        'isAppointment' => 'string',
        'createTime' => 'timestamp:Y-m-d H:i:s',
        'updateTime' => 'timestamp:Y-m-d H:i:s',
    ];

    //-----------------------------------------------------------------------------------
    //｜                                   获取器                                       ｜
    //-----------------------------------------------------------------------------------

    public function getCheckCnAttr($value, $data)
    {
        $value = $value ?: ($data['check'] ?? '');
        return (new TrainerCheckEnum())->getDescription($value) ?? '';
    }

    public function getLevelCnAttr($value, $data)
    {
        $value = $value ?: ($data['level'] ?? '');
        return (new TrainerLevelEnum())->getDescription($value) ?? '';
    }

    public function getPracticeCnAttr($value, $data)
    {
        $value = $value ?: ($data['practice'] ?? '');
        return (new TrainerPracticeEnum())->getDescription($value) ?? '';
    }

    public function getStatusCnAttr($value, $data)
    {
        $value = $value ?: ($data['status'] ?? '');
        return (new TrainerStatusEnum())->getDescription($value) ?? '';

    }

    public function getSexCnAttr($value, $data)
    {
        $value = $value ?: ($data['sex'] ?? '');
        return (new SexEnum())->getDescription($value) ?? '';
    }

    //-----------------------------------------------------------------------------------
    //｜                                   处理方法                                       ｜
    //-----------------------------------------------------------------------------------


    //获取用户信息(昵称/手机号)
    public static function getByAccountOrPhone(string $account): array|Model|Trainer|null
    {
        return self::where(['account|phone' => $account])->find();
    }

    public function listIdByOrganization($organizationId)
    {
        return $this->where(['organizationId' => $organizationId])->column('id');
    }


    public static function getByPhone(string $phone): array|Model|Trainer|null
    {
        return self::where(['phone' => $phone])->find();
    }

    public static function getById(int $id): array|Model|Trainer|null
    {
        return self::where(['id' => $id])->find();
    }

    public static function getUserInfo(int $id, array $with = []): array|Model|Trainer|null
    {
        return self::where(['id' => $id])->with($with)->find();
    }

    public function getListPage(array $where, string $page = "1", int $limit = 10)
    {
        return $this->with([
            'organizationBaseInfo' => function ($query) {
                $query->field('id,name,managerName');
            },
            'titleInfo'
        ])->where($where)
            ->order(['id' => 'desc'])
            ->paginate([
                'page' => $page,
                'list_rows' => $limit,
            ])->each(function ($item) {
                if ($item['organizationId'] == 0) {
                    $organizationModel = new Organization();
                    $item->organizationBaseInfo = $organizationModel->getOrganizationInfo();
                }
            });
    }

    public function getListSelectPage(array $where, string $page = "1", int $limit = 10)
    {
        return $this->where($where)
            ->order(['id' => 'desc'])
            ->field('id,name,practice')
            ->paginate([
                'page' => $page,
                'list_rows' => $limit
            ]);
    }

    public function getListAppointmentPage(string|int $trainerId, string $date, array $where, string $organizationId = '0', string $page = "1", int $limit = 10)
    {
        $where[] = ['status', '=', 3];
        if ($trainerId) {
            $where[] = ['id', '=', $trainerId];
        }
        $list = $this->where($where)->where(function ($query) use ($organizationId) {
            if ($organizationId) {
                $organizationModel = new OrganizationModel();
                $organizationIds = $organizationModel->getJuniorOrganization($organizationId);
                if ($organizationIds) {
                    $query->where([
                        ['organizationId', 'in', $organizationIds],
                        ['isPublic', '=', 1],
                    ])->whereOr('organizationId', $organizationId);
                } else {
                    $query->where('organizationId', $organizationId);
                }
            }
        })->order(['id' => 'desc'])
            ->paginate([
                'page' => $page,
                'list_rows' => $limit
            ]);
        $items = $list->items();
        $trainerIds = array_column($items, 'id');
        if ($trainerIds) {
            $coreTrainerTime = new CoreTrainerTime();
            $trainerTimeList = $coreTrainerTime->listByTrainerAndDate($trainerIds, $date)->toArray();
            $list->each(function ($item) use ($trainerTimeList) {
                $filteredTimeList = array_filter($trainerTimeList, function ($it) use ($item) {
                    return $it['trainerId'] == $item['id'];
                });
                $item->timeList = $filteredTimeList ? array_values($filteredTimeList) : [];
            });
            $learnSkRecord = new LearnSkRecord();
            $skCount = $learnSkRecord->listByTrainer($trainerIds);
            $list->each(function ($item) use ($skCount) {
                $matchedItem = null;
                foreach ($skCount as $it) {
                    if ($it['trainerId'] == $item['id']) {
                        $matchedItem = $it;
                        break;
                    }
                }
                $count = $matchedItem ? $matchedItem['count'] : 0;
                $item->skRecordCount = $count;
            });
        }
        return $list;
    }

    public function getInfo(array $where): array|Model|null
    {
        $info = $this->with([
            'organizationBaseInfo' => function ($query) {
                $query->field('id,name,managerName');
            },
            'titleInfo'])->where($where)->find();
        if (!$info) {
            return [];
        }
        if ($info['organizationId'] == 0) {
            $organization = new Organization();
            $info['organizationBaseInfo'] = $organization->getOrganizationInfo();
        }
        return $info;
    }

    public function saveOrUpdate(array $data, $organizationId = 0)
    {
        self::startTrans();
        try {
            $id = $data['id'] ?? 0;
            $saveData = $data;
            if (!$id) {
                $saveData['organizationId'] = $organizationId;
                $saveData['account'] = createRandomString('XM');
                $saveData['recommendCode'] = createRandomString('SDF');
                $salt = createPasswordSalt();
                $password = $data['password'] ?? substr($data['phone'], -6);
                $saveData['salt'] = $salt;
                $saveData['password'] = createPassword($salt, $password);
                $trainer = new self();
            } else {
                $trainer = self::where('id', $id)->find();
                if (empty($trainer)) {
                    throw new ValidateException('教练不存在');
                }
                if (!empty($data['passwordUpdate'])) {
                    $salt = createPasswordSalt();
                    $saveData['salt'] = $salt;
                    $saveData['password'] = createPassword($salt, $data['passwordUpdate']);
                }
            }
            $birthday = $data['birthday'] ?? 0;
            $age = 0;
            if ($birthday) {
                $age = calculateAge($birthday);
            }
            $saveData['age'] = $age;
            $isExists = self::where('phone', $data['phone'])
                    ->where('id', '<>', $id)
                    ->count() > 0;
            if ($isExists) {
                throw new ValidateException('手机号已存在,请更换后重试');
            }
            $trainer->save($saveData);
            self::commit();
        } catch (ValidateException|PDOException|Exception $e) {
            self::rollback();
            throw new ValidateException($e->getMessage());
        }
        return true;


    }

    public function updateEnable(int $id)
    {
        $info = $this->where('id', $id)->find();
        if (empty($info)) {
            throw new ValidateException('操作失败，教练不存在');
        }
        $status = $info->status == 2 ? 3 : 2;
        return $this->update(['status' => $status], ['id' => $id]);
    }
    //-----------------------------------------------------------------------------------
    //｜                                   模型关联                                       ｜
    //-----------------------------------------------------------------------------------

    public function organizationBaseInfo()
    {
        return $this->hasOne(Organization::class, 'id', 'organizationId');
    }

    public function titleInfo()
    {
        return $this->hasOne(TrainerTitle::class, 'id', 'title');
    }
}